#pragma once

#include<iostream>
#include<string>
#include<unordered_map>
#include<cstring>
#include<cstdlib>
#include<strings.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>

using namespace std;

// 编写一个聊天室，会有很多用户，服务器需要接受到一个客户端的消息之后，将该消息推送给所有客户端，让所有用户能看到信息

class User
{
public:
    User(const string& ip, const uint16_t port, const string& name)
    :_ip(ip)
    ,_port(port)
    ,_name(name)
    {}

    ~User(){}

    string getip(){return _ip;}
    uint16_t getport(){return _port;}
    string getname(){return _name;}

private:
    string _ip;
    uint16_t _port;
    string _name;
};

// 这里是对用户的管理
//这里我服务器端只给上线的用户推送数据【也可以给不上线的推送，让他们上线就能收到消息，这样就需要提前将数据保存下来，等到用户上线的时候在发过去】
class UserManager
{
public:
    UserManager(){}
    ~UserManager(){}

    void addUser(const string& ip, const uint16_t& port, const int& sockfd)
    {
        struct sockaddr_in client;
        bzero(&client, sizeof(client));
        client.sin_family = AF_INET;
        client.sin_addr.s_addr = inet_addr(ip.c_str());
        client.sin_port = htons(port);

        string id = ip + "-" + to_string(port);// 这里通过ip+port表示该用户的唯一性，从而作为id
        string message = "Register a name you want";
        sendto(sockfd, message.c_str(), message.size(), 0, (struct sockaddr*)&client, sizeof(client));

        char name[64];
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        ssize_t s = recvfrom(sockfd, name, sizeof(name)-1, 0, (struct sockaddr*)&peer, &len);
        name[s] = 0;
        
        _users.insert(make_pair(id, User(ip, port, name)));
    }

    void delUser(const string& ip, const uint16_t& port)
    {
        string id = ip + "-" + to_string(port);
        _users.erase(id);
    }

    //判断用户是否在线
    bool isOnline(const string& ip, const uint16_t& port)
    {
        string id = ip + "-" + to_string(port);
        return _users.find(id) == _users.end() ? false : true;
    }

    void boardcast(int sockfd, const string& message, const string& ip, const uint16_t& port)
    {
        // 给当前所有的在线用户广播
        for(auto user : _users)
        {
            struct sockaddr_in client;
            bzero(&client, sizeof(client));
            client.sin_family = AF_INET;
            client.sin_addr.s_addr = inet_addr(user.second.getip().c_str());
            client.sin_port = htons(user.second.getport());

            // 要注意，给所有用户广播别人的消息，昵称应该是发消息的人的ip+port(昵称)
            // string s = ip + "[" + to_string(port) + "]"; //相当于昵称，谁发的消息【其实可以直接在User里给个name成员】
            string id = ip + "-" + to_string(port); 
            auto senduser = _users.find(id); //在所有用户中，找到发消息的用户

            string s = senduser->second.getname() + "# "; //拿到发消息用户的name
            s += message;
            // cout << s << endl;
            sendto(sockfd, s.c_str(), s.size(), 0, (struct sockaddr*)&client, sizeof(client));
        }
    }

private:
    unordered_map<string, User> _users;
};

